package com.omg.server.framework.dao.impl;

import java.io.Serializable;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.List;

import javax.sql.DataSource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.SQLExceptionTranslator;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.orm.ibatis.SqlMapClientTemplate;

import com.omg.server.framework.dao.FacadeDAO;
import com.omg.server.framework.vo.ValueObject;
import com.omg.server.util.ReflectUtil;
import com.ibatis.sqlmap.client.SqlMapClient;
import com.ibatis.sqlmap.engine.execution.SqlExecutor;
import com.ibatis.sqlmap.engine.impl.ExtendedSqlMapClient;

public class FacadeDAOImpl implements FacadeDAO{
	
	private static final Log log = LogFactory.getLog(FacadeDAOImpl.class); 
	private DataSource dataSource;
	private SqlMapClient sqlMapClient;
	private SqlMapClientTemplate sqlMapClientTemplate;
	private SessionFactory sessionFactory;
	private HibernateTemplate hibernateTemplate;
	private JdbcTemplate jdbcTemplate;
	private SqlExecutor sqlExecutor;
	
	public DataSource getDataSource() {
		return dataSource;
	}
	
	public void setDataSource(DataSource dataSource) {
		this.dataSource = dataSource;
	}
	
	public SqlMapClient getSqlMapClient() {
		return sqlMapClient;
	}
	
	public void setSqlMapClient(SqlMapClient sqlMapClient) {
		this.sqlMapClient = sqlMapClient;
	}
	
	public SqlMapClientTemplate getSqlMapClientTemplate() {
	    if (null == this.sqlMapClientTemplate){
	        this.sqlMapClientTemplate = new SqlMapClientTemplate(this.sqlMapClient);

	        this.sqlMapClientTemplate.setExceptionTranslator(new SQLExceptionTranslator(){
	            public DataAccessException translate(String task, String sql, SQLException ex) {
	            	log.info(ex);
	                DataAccessException e = new DataAccessException(sql){
	                };
	                return e;
	            }
	        });
	    }
	    return this.sqlMapClientTemplate;
	}
	
	public void setSqlMapClientTemplate(SqlMapClientTemplate sqlMapClientTemplate) {
		this.sqlMapClientTemplate = sqlMapClientTemplate;
	}
	
	public SessionFactory getSessionFactory() {
		return sessionFactory;
	}
	
	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}
	
	public HibernateTemplate getHibernateTemplate() {
	    if (this.hibernateTemplate == null){
	         this.hibernateTemplate = new HibernateTemplate(this.sessionFactory);

	         this.hibernateTemplate.setJdbcExceptionTranslator(new SQLExceptionTranslator(){
	             public DataAccessException translate(String task, String sql, SQLException ex) {
	                 DataAccessException e = new DataAccessException(sql){
	                 };
	                 return e;
	             }
	         });
	    }
	    return this.hibernateTemplate;
	}
	
	public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
		this.hibernateTemplate = hibernateTemplate;
	}
	
	public JdbcTemplate getJdbcTemplate() {
		if (null == this.jdbcTemplate){
	      this.jdbcTemplate = new JdbcTemplate(this.dataSource);
	    }

	    this.jdbcTemplate.setExceptionTranslator(new SQLExceptionTranslator(){
	        public DataAccessException translate(String task, String sql, SQLException ex) {
	            DataAccessException e = new DataAccessException(sql){
	            };
	            return e;
	        }
	    });
	    return this.jdbcTemplate;
	}
	
	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}
	
	public SqlExecutor getSqlExecutor() {
		return sqlExecutor;
	}

	public void setSqlExecutor(SqlExecutor sqlExecutor) {
		this.sqlExecutor = sqlExecutor;
	}

	//修改 ibatis 分页机制为ORACLE物理分页
    public void initialized() {  
        if (null != sqlExecutor) {  
            SqlMapClient sqlMapClient = getSqlMapClientTemplate().getSqlMapClient();  
            if (sqlMapClient instanceof ExtendedSqlMapClient) {  
            	ReflectUtil.setFieldValue(((ExtendedSqlMapClient) sqlMapClient).getDelegate(), 
                		                  "sqlExecutor", SqlExecutor.class, sqlExecutor);  
            }
            else{
            	log.debug("ibatis分面设置不成功");
            }
        }  
	}

    public int delete_Hibernate_Object(ValueObject vo){
        getHibernateTemplate().delete(vo);
        return 0;
    }

    public int delete_iBatis(String queryID, Object[] params){
        int rs = 0;
        getSqlMapClientTemplate().delete(queryID, params[0]);
        rs = 1;
        return rs;
    }

    public int delete_JDBC(String sql, Object[] params){
        int rs = 0;
        getJdbcTemplate().execute(sql);
        rs = 1;
        return rs;
    }

    public int deleteByID_Hibernate_Object(Class cls, Serializable id){
        int rs = 0;
        getHibernateTemplate().delete(findByID_Hibernate_Get(cls, id));
        rs = 1;
        return rs;
    }

    
    public List<Object> find_iBatis(String queryName, Object para, int offset, int size){
        return getSqlMapClientTemplate().queryForList(queryName, para, offset, size);
    }

    public List find_iBatis(String queryName, Object params){
        return find_iBatis(queryName, params, 0, -999999);
    }

    public List findAll_Hibernate_ComposedHQL(String composedHQL){
        return getHibernateTemplate().find(composedHQL);
    }

    public List findAll_Hibernate_NamedQuery(String queryID){
        List list = getHibernateTemplate().findByNamedQuery(queryID);
        return list;
    }

    public List findAll_Hibernate_NamedQuery(String queryID, Object[] params){
        List list = getHibernateTemplate().findByNamedQuery(queryID, params);
        return list;
    }

    public List findAll_Hibernate_Object(Class cls){
        return getHibernateTemplate().loadAll(cls);
    }

    public List findAll_iBatis(String queryID){
        return getSqlMapClientTemplate().queryForList(queryID);
    }

    public List findAll_JDBC(String sql){
        return getJdbcTemplate().queryForList(sql);
    }

    public ValueObject findByID_Hibernate_ComposedHQL(String composedHQL, Serializable id){
        List list = getHibernateTemplate().find(composedHQL, id);
        Iterator it = list.iterator();
        ValueObject vo = null;
        if (it.hasNext()) {
            vo = (ValueObject)it.next();
        }

        if (vo != null){
            getHibernateTemplate().getSessionFactory().openSession().refresh(vo);
        }
        return vo;
    }

    public ValueObject findByID_Hibernate_Get(Class cls, Serializable id){
        ValueObject vo = null;
        vo = (ValueObject)getHibernateTemplate().get(cls, id);
        return vo;
    }

    public ValueObject findByID_Hibernate_Load(Class cls, Serializable id){
        ValueObject vo = null;
        vo = (ValueObject)getHibernateTemplate().load(cls, id);
        return vo;
    }

    
    public ValueObject findByID_Hibernate_NamedQuery(String queryId, Serializable id){
        List list = getHibernateTemplate().findByNamedQuery(queryId, id);
        Iterator it = list.iterator();
        ValueObject vo = null;
        if (it.hasNext()) {
            vo = (ValueObject)it.next();
        }

        if (vo != null){
            getHibernateTemplate().getSessionFactory().openSession().refresh(vo);
        }
        return vo;
    }

    public ValueObject findByID_iBatis(String queryId, Serializable id){
        return (ValueObject)getSqlMapClientTemplate().queryForObject(queryId, id);
    }


    public int save_Hibernate_Object(ValueObject vo){
        int rs = 0;
        getHibernateTemplate().save(vo);
        rs = 1;
        return rs;
    }

    public int save_iBatis(String queryID, Object[] params){
      int rs = 0;
      getSqlMapClientTemplate().insert(queryID, params[0]);
      rs = 1;
      return rs;
    }

    public int save_JDBC(String sql, Object[] params)
    {
      int rs = 0;
      getJdbcTemplate().execute(sql);
      rs = 1;
      return rs;
    }


    public int update_Hibernate_Object(ValueObject vo){
      int rs = 0;
      getHibernateTemplate().update(vo);
      rs = 1;
      return rs;
    }

    public int update_iBatis(String queryID, Object[] params){
      int rs = 0;
      getSqlMapClientTemplate().update(queryID, params[0]);
      rs = 1;
      return rs;
    }

    public int update_JDBC(String sql, Object[] params){
      int rs = 0;
      getJdbcTemplate().execute(sql);
      rs = 1;
      return rs;
    }

	@Override
	public Connection getConnection() {
		Connection rs = null;
	    try {
	        rs = this.dataSource.getConnection();
	    }
	    catch (SQLException se) {
	        throw new RuntimeException(se);
	    }
	    return rs;
	}

	@Override
	public int delete_Hibernate_NamedQuery(final String queryName, final Object[] params) {
		int rs = getHibernateTemplate().execute(new HibernateCallback<Integer>(){
			           public Integer doInHibernate(Session session) throws HibernateException, SQLException {
				          Query query = session.getNamedQuery(queryName);
				              if (null != params){
				                  for (int i=0, len=params.length; i < len; i++){
					                  query.setParameter(i, params[i]);
				                  }
				              }
				          return Integer.valueOf(query.executeUpdate());
			          }
			
		       }).intValue();
		return rs;
	}

	@Override
	public int update_Hibernate_NamedQuery(final String queryName, final Object[] params) {
		int rs = getHibernateTemplate().execute(new HibernateCallback<Integer>(){
	                  public Integer doInHibernate(Session session) throws HibernateException, SQLException {
		                  Query query = session.getNamedQuery(queryName);
		                  if (null != params){
		                      for (int i=0, len=params.length; i < len; i++){
			                      query.setParameter(i, params[i]);
		                      }
		                  }
		                  return Integer.valueOf(query.executeUpdate());
	                  }
	
                 }).intValue();
        return rs;
	}

}
